#pragma once

#include <cftc/timemeter/interval.h>

#include "map/map.h"

#if 1
class BattleGround
{
public:
    int GetTypeID() { return 0; }
};
#endif

class DungeonMap;
class BattleGroundMap;
class GridState;
class MapMgr : public cftf::util::Singleton<MapMgr>
{
    friend class cftf::util::Singleton<MapMgr>;
    MapMgr();

public:

    void Init();
    void UnInit();
    void Update(unsigned int);

    std::shared_ptr<Map> CreateMap(unsigned int, const battle::object::WorldObject* obj);
    std::shared_ptr<Map> CreateBgMap(unsigned int mapid, BattleGround* bg);
    std::shared_ptr<Map> FindMap(unsigned int mapid, unsigned int instanceId = 0) const;
    void UpdateGridState(game::system::grid::GridState_e state, Map& map, NGridType& ngrid, game::system::grid::GridInfo& ginfo, const unsigned int& x, const unsigned int& y, const unsigned int& t_diff);

    // only const version for outer users
    void DeleteInstance(unsigned int mapid, unsigned int instanceId);

    void Initialize(void);

    void SetGridCleanUpDelay(unsigned int t);
    void SetMapUpdateInterval(unsigned int t);

    void UnloadAll();

    static bool ExistMapAndVMap(unsigned int mapid, float x, float y);
    static bool IsValidMAP(unsigned int mapid);

    static bool IsValidMapCoord(unsigned int mapid, float x, float y)
    {
        return IsValidMAP(mapid) && map::grid::IsValidMapCoord(x, y);
    }

    static bool IsValidMapCoord(unsigned int mapid, float x, float y, float z)
    {
        return IsValidMAP(mapid) && map::grid::IsValidMapCoord(x, y, z);
    }

    static bool IsValidMapCoord(unsigned int mapid, float x, float y, float z, float o)
    {
        return IsValidMAP(mapid) && map::grid::IsValidMapCoord(x, y, z, o);
    }   
    static bool IsValidMapCoord(battle::object::WorldLocation const& loc);
    // modulos a radian orientation to the range of 0..2PI
    static float NormalizeOrientation(float o);

    void RemoveAllObjectsInRemoveList();

    void LoadContinents();
    void LoadTransports();

    std::set<battle::object::Transport*> m_Transports;
    std::map<unsigned int, std::set<battle::object::Transport*>> m_TransportsByMap;

    unsigned int GenerateInstanceId() { return ++i_MaxInstanceId; }
    void InitMaxInstanceId();
    void InitializeVisibilityDistanceInfo();

    /* statistics */
    unsigned int GetNumInstances();
    unsigned int GetNumPlayersInInstances();


    // get list of all maps
    const auto& Maps() const { return map_hash_; }

private:

    // debugging code, should be deleted some day
    GridState* si_GridStates[game::system::grid::MAX_GRID_STATE] = {nullptr};
    int i_GridStateErrorCount = 0;

private:

    ~MapMgr();
    MapMgr(const MapMgr&) = delete;
    MapMgr& operator=(const MapMgr&) = delete;

    void InitStateMachine();
    void DeleteStateMachine();
    void LoadActiveEntities(Map* m);

    std::shared_ptr<Map> CreateInstance(unsigned int id, battle::object::Player* player);
    std::shared_ptr<DungeonMap> CreateDungeonMap(unsigned int id, unsigned int InstanceId, DungeonPersistentState* save = NULL);
    std::shared_ptr<BattleGroundMap> CreateBattleGroundMap(unsigned int id, unsigned int InstanceId, BattleGround* bg);

    unsigned int i_gridCleanUpDelay;
    std::map<long long, std::shared_ptr<Map>> map_hash_;
    cftc::timemeter::Interval timemeter_;
#if 0
    MapUpdater m_updater;
#endif
    unsigned int i_MaxInstanceId = 0;
};